using System;
using System.IO;
using System.Collections;
using System.Text;
using System.Web.UI;
using System.Drawing;

namespace UDonkey.Logic
{
    class DayScheduler
    {
        private const int initialHourColumnCount = 5;

    // Properties
        private ArrayList hourColumns;

    // Methods
        // Constructor
        public DayScheduler()
        {
            hourColumns = new ArrayList(initialHourColumnCount);

            // Initialize empty columns
            for (int i = 0; i < initialHourColumnCount; i++)
            {
                // Create an empty column
                CourseEventOccurrence[] hourColumn = new CourseEventOccurrence[24];
                for (int j = 0; j < 24; j++)
                {
                    hourColumn[j] = null;
                }

                hourColumns.Add(hourColumn);
            }
        }

        // Adds a course event to the day
        public void AddCourseEventOccurence(CourseEventOccurrence c) 
        {
            bool foundColumn = false;

            // Go over all hour columns
            for (int i = 0; i < hourColumns.Count; i++) 
            {
                CourseEventOccurrence[] currentColumn = 
                    (CourseEventOccurrence[])hourColumns[i];

                // Check if current column can hold the entire course occurence
                bool columnAvailable = true;
                for (int j = c.Hour; j < c.Hour + c.Duration; j++)
                {
                    // Check if slot is available
                    if (currentColumn[j] != null) 
                    {
                        columnAvailable = false;
                        break;
                    }
                }

                // If the column wasn't availble move to the next one
                if (!columnAvailable) continue;

                // The column was availble - add the event
                foundColumn = true;
                for (int j = c.Hour; j < c.Hour + c.Duration; j++)
                {
                    // Assign course event occurence
                    currentColumn[j] = c;                    
                }

                break;
            }

            // If a column was found, the course was added - return
            if (foundColumn) return;

            // A column wasn't found - create a new one
            CourseEventOccurrence[] newHourColumn = new CourseEventOccurrence[24];
            for (int j = c.Hour; j < c.Hour + c.Duration; j++)
            {
                // Assign course event occurence
                newHourColumn[j] = c;
            }

            // And add it to the hour columns
            hourColumns.Add(newHourColumn);
        }


        // Write this day to an html file
        public void writeHTML(HtmlTextWriter hw, Hashtable courseColors)
        {
            int cellPercentage = 100 / hourColumns.Count;

            // Table start
            hw.WriteBeginTag("Table");
            hw.WriteAttribute(HtmlTextWriterAttribute.Width.ToString(), "100%");
            hw.WriteAttribute(HtmlTextWriterAttribute.Border.ToString(), "2");
            hw.WriteAttribute(HtmlTextWriterAttribute.Cellpadding.ToString(), "1");
            hw.WriteAttribute(HtmlTextWriterAttribute.Rules.ToString(), "all");
            hw.WriteAttribute(HtmlTextWriterAttribute.Dir.ToString(), "rtl");
            hw.Write(">\r\n");

            // Table content
            for (int hour = 8; hour <= 20; hour++)
            {
                // New row
                hw.Write("<tr>");

                // Write the hour
                hw.WriteBeginTag("th");
                hw.WriteAttribute(HtmlTextWriterAttribute.Width.ToString(), "100");
                hw.Write(">");
                hw.Write(hour + ":30");
                hw.WriteEndTag("th");

                // Write the actual events
                foreach (CourseEventOccurrence[] hours in hourColumns)
                {
                    // If the slot is not taken write an empty one
                    if (hours[hour] == null)
                    {
                        // Write an empty slot
                        hw.WriteBeginTag("td");
                        hw.WriteAttribute(HtmlTextWriterAttribute.Width.ToString(),
                            cellPercentage + "%");
                        hw.Write(">");
                        hw.WriteEndTag("td");
                    }
                    else // The slot exists write its details
                    {
                        Color foreground = ((Color[])
                            (courseColors[hours[hour].CourseEvent.Course.Name]))[0];
                        Color background = ((Color[])
                            (courseColors[hours[hour].CourseEvent.Course.Name]))[1];

                        // Table data start
                        hw.WriteBeginTag("td");
                        hw.WriteAttribute(HtmlTextWriterAttribute.Width.ToString(), 
                            cellPercentage + "%");
                        hw.WriteAttribute(HtmlTextWriterAttribute.Bgcolor.ToString(),
                            "#" +
                            String.Format("{0:x2}", (int)(background.R)) +
                            String.Format("{0:x2}", (int)(background.G)) +
                            String.Format("{0:x2}", (int)(background.B)));
                        hw.Write(">");

                        // Font start (for coloring)
                        hw.WriteBeginTag("font");
                        hw.WriteAttribute("color",
                            "#" +
                            String.Format("{0:x2}", (int)(foreground.R)) +
                            String.Format("{0:x2}", (int)(foreground.G)) +
                            String.Format("{0:x2}", (int)(foreground.B)));
                        hw.Write(">");

                        // Table data content
                        hw.Write(hours[hour].CourseEvent.Course.Name);
                        hw.Write("<br>");
                        hw.Write(hours[hour].CourseEvent.Type + " " +
                            hours[hour].CourseEvent.EventNum);
                        hw.Write("<br>");
                        hw.Write(hours[hour].CourseEvent.Giver);
                        hw.Write("<br>");
                        hw.Write(hours[hour].Location);
                        hw.Write("<br>");

                        // Font end
                        hw.WriteEndTag("font");

                        // Table data end
                        hw.WriteEndTag("td");
                    }
                }

                // row end
                hw.Write("</tr>");
                hw.Write("\r\n");
            }

            // Table end
            hw.WriteEndTag("Table");
            hw.Write("\r\n");
        }


        // Calculate the farthest event column in the specified hour
        private int countSlots(int hour)
        {
            int i = 0;
            int count = 0;

            foreach (CourseEventOccurrence[] hours in hourColumns)
            {
                i++;
                if (hours[hour] != null)
                {
                    count = i;
                }
            }

            return count;
        }

        // Count the simaltaneous events in the specified hour
        private int countEvents(int hour) 
        {
            int count = 0;

            foreach (CourseEventOccurrence[] hours in hourColumns)
            {
                if (hours[hour] != null)
                {
                    count++;
                }
            }

            return count;
        }
    }

    public class WeekScheduler
    {
    // Properties
        private DayScheduler[] days;
        private Hashtable courseColors;
        private Random r;

    // Methods
        public WeekScheduler()
        {
            days = new DayScheduler[Enum.GetValues(typeof(DayOfWeek)).Length - 1];

            // Initialize the days
            for (int i = 0; i < days.Length; i++)
            {
                days[i] = new DayScheduler();
            }

            // Initialize the course colors hash table
            courseColors = new Hashtable();

            // Initialize the random generator
            r = new Random((int)DateTime.Now.Ticks);
        }


        private void assignCourseColor(CourseEventOccurrence c)
        {
            // If the course has not been assigned a color
            if (!courseColors.ContainsKey(c.CourseEvent.Course.Name))
            {
                Color foreground, background;
                ColorMixer.Colors(c.CourseEvent.Course.Name.GetHashCode(),
                    out foreground, out background);
                               
                courseColors.Add(c.CourseEvent.Course.Name, 
                    new Color[] {foreground, background});
            }
        }


        // Adds a course event occurence to the relevant day
        public void AddCourseEventOccurrence(CourseEventOccurrence c) 
        {
            // Assign a color for this course
            assignCourseColor(c);

            // Add it to the relevant day
            days[((int)c.Day) - 1].AddCourseEventOccurence(c);
        }

        
        // Outputs table in html format
        public void writeHTML(StreamWriter fs)
        {
            HtmlTextWriter scheduleWriter = new HtmlTextWriter(fs);

            // HTML Start
            scheduleWriter.WriteFullBeginTag("html");
            scheduleWriter.Write("\r\n");
            scheduleWriter.WriteFullBeginTag("head");
            scheduleWriter.Write("\r\n");

            // Formatting stuff
            scheduleWriter.Write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
            scheduleWriter.Write("\r\n");
            scheduleWriter.Write("<style type=\"text/css\">\r\n");
            scheduleWriter.Write("<!--\r\nth {color: #660066 ; background-color: #99CCFF ; font-size: 22px}\r\n-->\r\n");
            scheduleWriter.Write("</style>\r\n");

            // For every day
            for (int i = 0; i < days.Length - 2; i++)
            {
                // "Day" title
                scheduleWriter.WriteBeginTag("h1");
                scheduleWriter.WriteAttribute(HtmlTextWriterAttribute.Align.ToString(), "center");
                scheduleWriter.WriteFullBeginTag("strong");
                scheduleWriter.Write(Enum.GetNames(typeof(DayOfWeek))[i+1]);
                scheduleWriter.WriteEndTag("strong");
                scheduleWriter.WriteEndTag("h1");
                scheduleWriter.Write("\r\n");

                // Output the day's table content
                days[i].writeHTML(scheduleWriter, courseColors);

                // Page break
                scheduleWriter.WriteLine("<p style=\"page-break-before: always\">");
            }

            

            // HTML End
            scheduleWriter.WriteEndTag("head");
            scheduleWriter.Write("\r\n");
            scheduleWriter.WriteEndTag("html");
            scheduleWriter.Write("\r\n");
        }
    }
}
